home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 3 / Amiga Format CD03 (1996-07-04)(Future Publishing)(GB)(Track 1 of 6)[!][issue 1996-08].iso / comms / netsoftware / archie38_1.lha / archie-1.4 / dirsend.c < prev    next >
C/C++ Source or Header  |  1995-01-05  |  30KB  |  1,114 lines

  1. /*
  2.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  3.  *
  4.  * For copying and distribution information, please see the file
  5.  * <copyright.h>.
  6.  */
  7. /* Amiga port by Tomas Willis (tomas@cae.wisc.edu) January 1995 */
  8.  
  9. /* If you're going to hack on this, I'd suggest using unifdef with -UCUTCP
  10.    and possibly -UVMS, for your working copy.  When you've got your changes
  11.    done, come back and add them into this main file.  It's getting pretty
  12.    nasty down there.  */
  13.  
  14. #include <stdio.h>
  15. #include <errno.h>
  16. #include <sys/errno.h>
  17.  
  18. #ifdef AMIGA
  19. # include <fcntl.h>
  20. #endif
  21.  
  22. #ifdef VMS
  23. # ifdef WOLLONGONG
  24. #  include "twg$tcp:[netdist.include]netdb.h"
  25. # else /* not Wollongong */
  26. #  ifdef UCX
  27. #   include <netdb.h>
  28. #  else /* Multinet */
  29. #   include "multinet_root:[multinet.include]netdb.h"
  30. #  endif
  31. # endif
  32. # include <vms.h>
  33. #else /* not VMS */
  34. # include <sys/types.h> /* this may/will define FD_SET etc */
  35. # ifdef u3b2
  36. #  include <sys/inet.h> /* THIS does FD_SET etc on AT&T 3b2s.  */
  37. # endif /* u3b2 */
  38. # ifdef PCNFS
  39. #  include <tklib.h>
  40. #  include <tk_errno.h>
  41. #  include <sys/nfs_time.h>
  42. # endif
  43. # include "pmachine.h"
  44. # if defined(NEED_TIME_H) && !defined(AUX)
  45. #  include <time.h>
  46. # else
  47. #  include <sys/time.h>
  48. # endif
  49. # ifdef WANT_BOTH_TIME
  50. #  include <sys/time.h>
  51. # endif
  52. # ifdef NEED_STRING_H
  53. #  include <string.h>
  54. # else
  55. #  include <strings.h>
  56. # endif
  57. # ifdef CUTCP
  58. #  include <msdos/cutcp.h>
  59. #  include <msdos/netevent.h>
  60. #  include <msdos/hostform.h>
  61. # else /* not CUTCP */
  62. #  include <netdb.h>
  63. #  include <sys/socket.h>
  64. # endif
  65. # ifdef NEED_SELECT_H
  66. #  include <sys/select.h>
  67. # endif /* NEED_SELECT_H */
  68. # ifndef IN_H
  69. #  include <netinet/in.h>
  70. #  define IN_H
  71. # endif
  72. # if !defined(hpux) && !defined(PCNFS)
  73. #  include <arpa/inet.h>
  74. # endif
  75. #endif /* !VMS */
  76.  
  77. /* Interactive UNIX keeps some of the socket definitions in funny places.  */
  78. #ifdef ISC
  79. # include <net/errno.h>
  80. #endif /* ISC */
  81. /* PC-NFS Toolkit 4.0 keeps important forward definitions here. */
  82. #ifdef PCNFS
  83. # include <in_addr.h>
  84. #endif
  85.  
  86. #include "pfs.h"
  87. #include "pprot.h"
  88. #include "pcompat.h"
  89. #include "perrno.h"
  90.  
  91. /* Gnu C currently fails to pass structures on Sparcs properly.  This directly
  92.    effects the calling of inet_ntoa().  To get around it, we use this hack;
  93.    take the address of what's being called to inet_ntoa, so it gets it
  94.    properly.  This won't be necessary with gcc 2.0.  */
  95. #if defined(sun) && defined(__GNUC__) && !defined(__GNU_LIBRARY__) \
  96.     && !defined(__svr4__)
  97. # define SUN_GNU_FIX &
  98. #else
  99. # define SUN_GNU_FIX
  100. #endif
  101.  
  102. static int notprived = 0;
  103. #ifndef MSDOS
  104. extern int errno;
  105. #endif
  106. extern int perrno;
  107. extern int rdgram_priority;
  108. #ifdef DEBUG
  109. extern int pfs_debug;
  110. #endif
  111. extern int pfs_disable_flag;
  112.  
  113. extern int verbose;
  114.  
  115. #define max(X, Y)  ((X) > (Y) ? (X) : (Y))
  116.  
  117. static int        dir_udp_port = 0;    /* Remote UDP port number */
  118.  
  119. #ifdef CUTCP
  120. # define    NS_TIMEOUT    15
  121. #endif
  122.  
  123. static unsigned short    next_conn_id = 0;
  124.  
  125. static int client_dirsrv_timeout = CLIENT_DIRSRV_TIMEOUT;
  126. static int client_dirsrv_retry = CLIENT_DIRSRV_RETRY;
  127.  
  128. /* These were parameters to dirsend() */
  129. static PTEXT pkt;
  130. static char *hostname;
  131. static struct sockaddr_in *hostaddr;
  132.  
  133. /* These were locals in dirsend(). Note that the initializations here
  134.  * are really meaningless since we have to redo them for each call to
  135.  * dirsend() since they were formerly automatically initialized.
  136.  */
  137. static PTEXT        first = NULL;    /* First returned packet     */
  138. static PTEXT        next;        /* The one we are waiting for      */
  139. static PTEXT        vtmp;           /* For reorganizing linked list  */
  140. static PTEXT        comp_thru;    /* We have all packets though    */
  141. static int        lp = -1;    /* Opened UDP port             */
  142. static int        hdr_len;    /* Header Length                 */
  143. static int        nd_pkts;    /* Number of packets we want     */
  144. static int        no_pkts;    /* Number of packets we have     */
  145. static int        pkt_cid;        /* Packet connection identifier  */
  146. static unsigned short    this_conn_id;    /* Connection ID we are using    */
  147. static unsigned short    recvd_thru;    /* Received through              */
  148. static short        priority;    /* Priority for request          */
  149. static short        one = 0;    /* Pointer to value 1            */
  150. static short        zero = 0;    /* Pointer to value 0         */
  151. static char        *seqtxt;    /* Pointer to text w/ sequence # */
  152. static struct sockaddr_in  us;        /* Our address                   */
  153. static struct sockaddr_in  to;        /* Address to send query     */
  154. static struct sockaddr_in  from;    /* Reply received from         */
  155. static long from_sz;    /* Size of from structure: changed to long by tcw */
  156. static struct hostent    *host;        /* Host info from gethostbyname  */
  157. static long        newhostaddr;    /* New host address from *host   */
  158. static int        req_udp_port=0; /* Requested port (optional)     */
  159. static char        *openparen;    /* Delimits port in name         */
  160. static char        hostnoport[500];/* Host name without port        */
  161. static int        ns;        /* Number of bytes actually sent */
  162. static int        nr;        /* Number of bytes received      */
  163. static SELECTARG    readfds;    /* Used for select         */
  164. static int        tmp;
  165. static char        *ctlptr;    /* Pointer to control field      */
  166. static short        stmp;        /* Temp short for conversions    */
  167. static int        backoff;    /* Server requested backoff      */
  168. static unsigned char    rdflag11;    /* First byte of flags (bit vect)*/
  169. static unsigned char    rdflag12;    /* Second byte of flags (int)    */
  170. static int        scpflag = 0;    /* Set if any sequencd cont pkts */
  171. static int        ackpend = 0;    /* Acknowledgement pending      */
  172. static int        gaps = 0;    /* Gaps present in recvd pkts   */
  173. static struct timeval    timeout;    /* Time to wait for response    */
  174. static struct timeval    ackwait;    /* Time to wait before acking   */
  175. static struct timeval    gapwait;    /* Time to wait b4 filling gaps */
  176. static struct timeval    *selwait;    /* Time to wait for select      */
  177. static int        retries;    /* was = client_dirsrv_retry    */
  178. char   to_hostname[512];        /* lmjm: saves inet_ntoa() str  */
  179.  
  180. /* These are added so dirsend() "blocks" properly */
  181. static PTEXT dirsendReturn;
  182. static int dirsendDone;
  183.  
  184. /* And here are the values for dirsendDone */
  185. #define DSRET_DONE        1
  186. #define DSRET_SEND_ERROR    -1
  187. #define DSRET_RECV_ERROR    -2
  188. #define DSRET_SELECT_ERROR    -3
  189. #define DSRET_TIMEOUT        -4
  190. #define DSRET_ABORTED        -5
  191.  
  192.  
  193. /* Extra stuff for the asynchronous X version of dirsend() */
  194. typedef char *XtPointer;
  195. typedef char *XtInputId;
  196. typedef char *XtIntervalId;
  197.  
  198. static XtInputId inputId;
  199. static XtIntervalId timerId = (XtIntervalId)0;
  200.  
  201. //protos
  202. PTEXT dirsend(PTEXT pkt_p, char *hostname_p, struct sockaddr_in *hostaddr_p);
  203. void abortDirsend(void);
  204. /* New procedures to break up dirsend() */
  205. static int initDirsend(void);
  206. static void retryDirsend(void);
  207. static void keepWaitingDirsend(void);
  208. static void timeoutProc(XtPointer client_data,XtIntervalId *id);
  209. static void readProc(XtPointer client_data, int *source, XtInputId *id);
  210.  
  211. /* Wrappers around X calls to allow non-X usage */
  212. static void processEvent(void);
  213.  
  214. //extern
  215. extern char * nlsindex(char * s1, char *s2);
  216. extern PTEXT ptalloc(void);
  217. extern void ptfree(PTEXT vt);
  218. extern void ptlfree(PTEXT vt);
  219. extern pid_t getpid(void);    // getpid.c
  220.  
  221.  
  222. /*
  223.  * dirsend - send packet and receive response
  224.  *
  225.  *   DIRSEND takes a pointer to a structure of type PTEXT, a hostname,
  226.  *   and a pointer to a host address.  It then sends the supplied
  227.  *   packet off to the directory server on the specified host.  If
  228.  *   hostaddr points to a valid address, that address is used.  Otherwise,
  229.  *   the hostname is looked up to obtain the address.  If hostaddr is a
  230.  *   non-null pointer to a 0 address, then the address will be replaced
  231.  *   with that found in the hostname lookup.
  232.  *
  233.  *   DIRSEND will wait for a response and retry an appropriate
  234.  *   number of times as defined by timeout and retries (both static
  235.  *   variables).  It will collect however many packets form the reply, and
  236.  *   return them in a structure (or structures) of type PTEXT.
  237.  *
  238.  *   DIRSEND will free the packet that it is presented as an argument.
  239.  *   The packet is freed even if dirsend fails.
  240.  */
  241. PTEXT
  242. dirsend(PTEXT pkt_p, char *hostname_p, struct sockaddr_in *hostaddr_p)
  243. //    PTEXT pkt_p;
  244. //    char *hostname_p;
  245. //    struct sockaddr_in    *hostaddr_p;
  246. {
  247.     /* copy parameters to globals since other routines use them */
  248.     pkt = pkt_p;
  249.     hostname = hostname_p;
  250.     hostaddr = hostaddr_p;
  251.     /* Do the initializations of formerly auto variables */
  252.     first = NULL;
  253.     lp = -1;
  254.     one = 0;
  255.     zero = 0;
  256.     req_udp_port=0;
  257.     scpflag = 0;
  258.     ackpend = 0;
  259.     gaps = 0;
  260.     retries = client_dirsrv_retry;
  261.  
  262.     if (initDirsend() < 0)
  263.     return(NULL);
  264.  
  265.     /* set the first timeout */
  266.     retryDirsend();
  267.  
  268.     dirsendReturn = NULL;
  269.     dirsendDone = 0;
  270.     /* Until one of the callbacks says to return, keep processing events */
  271.     while (!dirsendDone)
  272.     processEvent();
  273.  
  274.     /* Return whatever we're supposed to */
  275.     return(dirsendReturn);
  276. }
  277.  
  278.  
  279. /*    -    -    -    -    -    -    -    -    */
  280. /* This function does all the initialization that used to be done at the
  281.  * start of dirsend(), including opening the socket descriptor "lp". It
  282.  * returns the descriptor if successful, otherwise -1 to indicate that
  283.  * dirsend() should return NULL immediately.
  284.  */
  285. static int
  286. initDirsend(void)
  287. {
  288.     if(one == 0) one = htons((short) 1);
  289.  
  290.     priority = htons(rdgram_priority);
  291.  
  292.     timeout.tv_sec = client_dirsrv_timeout;
  293.     timeout.tv_usec = 0;
  294.  
  295.     ackwait.tv_sec = 0;
  296.     ackwait.tv_usec = 500000;
  297.  
  298.     gapwait.tv_sec = (client_dirsrv_timeout < 5 ? client_dirsrv_timeout : 5);
  299.     gapwait.tv_usec = 0;
  300.  
  301.     comp_thru = NULL;
  302.     perrno = 0;
  303.     nd_pkts = 0;
  304.     no_pkts = 0;
  305.     pkt_cid = 0;
  306.  
  307.     /* Find first connection ID */
  308.     if(next_conn_id == 0) {
  309.     srand(getpid()+time(0)); /* XXX: arg ok, but not right type. */
  310.     next_conn_id = rand();
  311.     }
  312.  
  313.  
  314.     /* If necessary, find out what udp port to send to */
  315.     if (dir_udp_port == 0) {
  316.         register struct servent *sp;
  317.     tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  318. #ifdef USE_ASSIGNED_PORT
  319.     /* UCX needs 0 & -1 */
  320.         sp = getservbyname("prospero","udp");
  321.     if (sp == (struct servent *)0 || sp == (struct servent *)-1) {
  322. #ifdef DEBUG
  323.         if (pfs_debug)
  324.         fprintf(stderr, "dirsrv: udp/prospero unknown service - using %d\n", 
  325.             PROSPERO_PORT);
  326. #endif
  327.         dir_udp_port = htons((u_short) PROSPERO_PORT);
  328.         }
  329. #else
  330.     /* UCX needs 0 & -1 */
  331.         sp = getservbyname("dirsrv","udp");
  332.     if (sp == (struct servent *)0 || sp == (struct servent *)-1) {
  333. #ifdef DEBUG
  334.         if (pfs_debug)
  335.         fprintf(stderr, "dirsrv: udp/dirsrv unknown service - using %d\n",
  336.             DIRSRV_PORT);
  337. #endif
  338.         dir_udp_port = htons((u_short) DIRSRV_PORT);
  339.         }
  340. #endif
  341.     else dir_udp_port = sp->s_port;
  342.     pfs_enable = tmp;
  343. #ifdef DEBUG
  344.         if (pfs_debug > 3)
  345.             fprintf(stderr,"dir_udp_port is %d\n", ntohs(dir_udp_port));
  346. #endif
  347.     }
  348.  
  349.     /* If we were given the host address, then use it.  Otherwise  */
  350.     /* lookup the hostname.  If we were passed a host address of   */
  351.     /* 0, we must lookup the host name, then replace the old value */
  352.     if(!hostaddr || (hostaddr->sin_addr.s_addr == 0)) {
  353.     /* I we have a null host name, return an error */
  354.     if((hostname == NULL) || (*hostname == '\0')) {
  355. #ifdef DEBUG
  356.             if (pfs_debug)
  357.                 fprintf(stderr, "dirsrv: Null hostname specified\n");
  358. #endif
  359.         perrno = DIRSEND_BAD_HOSTNAME;
  360.         ptlfree(pkt);
  361.             /* return(NULL); */
  362.         return(-1);
  363.     }
  364.     /* If a port is included, save it away */
  365.     if(openparen = index(hostname,'(')) {
  366.         sscanf(openparen+1,"%d",&req_udp_port);
  367.         strncpy(hostnoport,hostname,400);
  368.         if((openparen - hostname) < 400) {
  369.         *(hostnoport + (openparen - hostname)) = '\0';
  370.         hostname = hostnoport;
  371.         }
  372.     }
  373.     tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  374.     if((host = gethostbyname(hostname)) == NULL) {
  375.         pfs_enable = tmp;
  376.         /* Check if a numeric address */
  377.         newhostaddr = inet_addr(hostname);
  378.         if(newhostaddr == -1) {
  379. #ifdef DEBUG
  380.         if (pfs_debug)
  381.           fprintf(stderr, "dirsrv: Can't resolve host %s\n",hostname);
  382. #endif
  383.         perrno = DIRSEND_BAD_HOSTNAME;
  384.         ptlfree(pkt);
  385.         /* return(NULL); */
  386.         return(-1);
  387.         }
  388.         bzero((char *)&to, S_AD_SZ);
  389.         to.sin_family = AF_INET;
  390.         bcopy((char *) &newhostaddr, (char *)&to.sin_addr, 4);
  391.         if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  392.     }
  393.     else {
  394.         pfs_enable = tmp;
  395.         bzero((char *)&to, S_AD_SZ);
  396.         to.sin_family = host->h_addrtype;
  397. #ifdef CUTCP
  398.         bcopy((char *) &host->h_addr, (char *)&to.sin_addr, host->h_length);
  399. #else
  400.         bcopy(host->h_addr, (char *)&to.sin_addr, host->h_length);
  401. #endif
  402.         if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  403.     }
  404.     }
  405.     else bcopy(hostaddr,&to, S_AD_SZ);
  406.     /* lmjm: Save away the hostname */
  407.     strncpy(to_hostname,
  408.         inet_ntoa(SUN_GNU_FIX *(struct in_addr *)&to.sin_addr),
  409.         sizeof(to_hostname)-1);
  410.  
  411.     if(req_udp_port) to.sin_port = htons(req_udp_port);
  412.     else to.sin_port = dir_udp_port;
  413.  
  414.     /* If a port was specified in hostaddr, use it, otherwise fill it in */
  415.     if(hostaddr) {
  416.     if(hostaddr->sin_port) to.sin_port = hostaddr->sin_port;
  417.     else hostaddr->sin_port = to.sin_port;
  418.     }
  419.  
  420. #ifndef CUTCP
  421.     /* Must open a new port each time. we do not want to see old */
  422.     /* responses to messages we are done with                    */
  423.     if ((lp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  424. #ifdef DEBUG
  425.         if (pfs_debug)
  426.             fprintf(stderr,"dirsrv: Can't open socket\n");
  427. #endif
  428.     perrno = DIRSEND_UDP_CANT;
  429.     ptlfree(pkt);
  430.         /* return(NULL); */
  431.     return(-1);
  432.     }
  433. #endif /* not CUTCP */
  434.  
  435.     /* Try to bind it to a privileged port - loop through candidate */
  436.     /* ports trying to bind.  If failed, that's OK, we will let the */
  437.     /* system assign a non-privileged port later                    */
  438. #ifndef CUTCP
  439.     if(!notprived) {
  440.     for(tmp = PROS_FIRST_PRIVP; tmp < PROS_FIRST_PRIVP+PROS_NUM_PRIVP; 
  441.         tmp++) {
  442. #endif
  443.         bzero((char *)&us, sizeof(us));
  444.         us.sin_family = AF_INET;
  445. #ifndef CUTCP
  446.         us.sin_port = htons((u_short) tmp);
  447.         if (bind(lp, (struct sockaddr *)&us, sizeof(us))) {
  448.         if(errno != EADDRINUSE) {
  449.             notprived++;
  450.             break;
  451.         }
  452.         }
  453.         else break;
  454.     }
  455.     }
  456. #else
  457.     us.sin_port = htons(PROS_FIRST_PRIVP);
  458.     netulisten(PROS_FIRST_PRIVP);
  459. #endif
  460.  
  461. #ifndef USE_V3_PROT
  462.     /* Add header */
  463.     if(rdgram_priority) {
  464.     pkt->start -= 15;
  465.     pkt->length += 15;
  466.     *(pkt->start) = (char) 15;
  467.     bzero(pkt->start+9,4);
  468.     *(pkt->start+11) = 0x02;
  469.     bcopy(&priority,pkt->start+13,2);
  470.     }
  471.     else {
  472.     pkt->start -= 9;
  473.     pkt->length += 9;
  474.     *(pkt->start) = (char) 9;
  475.     }
  476.     this_conn_id = htons(next_conn_id++);
  477.     if(next_conn_id == 0) next_conn_id++;
  478.     bcopy(&this_conn_id,pkt->start+1,2);
  479.     bcopy(&one,pkt->start+3,2);
  480.     bcopy(&one,pkt->start+5,2);
  481.     bzero(pkt->start+7,2);
  482. #endif
  483.  
  484. #ifdef DEBUG
  485.     if (pfs_debug > 2) {
  486. #ifndef USE_V3_PROT
  487.         if (to.sin_family == AF_INET) {
  488.         if(req_udp_port) 
  489.         fprintf(stderr,"Sending message to %s+%d(%d)...",
  490.             to_hostname, req_udp_port, ntohs(this_conn_id));
  491.         else fprintf(stderr,"Sending message to %s(%d)...",
  492.              to_hostname, ntohs(this_conn_id));
  493.     }
  494. #else
  495.         if (to.sin_family == AF_INET) 
  496.         fprintf(stderr,"Sending message to %s...", to_hostname);
  497. #endif /* USE_V3_PROT */
  498.         else
  499.             fprintf(stderr,"Sending message...");
  500.         (void) fflush(stderr);
  501.     }
  502. #endif /* DEBUG */
  503.  
  504.     first = ptalloc();
  505.     next = first;
  506.  
  507. #ifndef CUTCP
  508.     return(lp);
  509. #else
  510.     return(1);
  511. #endif /* CUTCP */
  512. }
  513.  
  514. /*    -    -    -    -    -    -    -    -    */
  515. /*
  516.  * This used to be a label to goto to retry the last packet. Now we resend
  517.  * the packet and call keepWaitingDirsend() to wait for a reply. (We
  518.  * call keepWaitingDirsend() because formerly the code dropped through
  519.  * the keep_waiting label.)
  520.  */
  521. static void
  522. retryDirsend(void)
  523. {
  524. #ifdef CUTCP
  525.     int lretry = 3;
  526. #endif
  527.     gaps = ackpend = 0;
  528.  
  529. #ifndef CUTCP
  530.     ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  531. #else
  532.     while(--lretry) {
  533.         ns = netusend(&to.sin_addr,ntohs(to.sin_port),ntohs(us.sin_port),
  534.               (char *) pkt->start, pkt->length);
  535.         if(!ns)
  536.         break;
  537.         Stask();
  538.         Stask();
  539.         Stask();
  540.     }
  541. #endif /* CUTCP */
  542.  
  543. #ifndef CUTCP
  544.     if(ns != pkt->length) {
  545. #else
  546.     if(ns != 0) {
  547. #endif
  548. #ifdef DEBUG
  549.     if (pfs_debug) {
  550.     fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  551.         perror("");
  552.     }
  553. #endif
  554.     close(lp);
  555.     perrno = DIRSEND_NOT_ALL_SENT;
  556.     ptlfree(first);
  557.     ptlfree(pkt);
  558.     /* return(NULL); */
  559.     dirsendReturn = NULL;
  560.     dirsendDone = DSRET_SEND_ERROR;
  561.     }
  562. #ifdef DEBUG
  563.     if (pfs_debug > 2) fprintf(stderr,"Sent.\n");
  564. #endif
  565.     keepWaitingDirsend();
  566. }
  567.  
  568. /*    -    -    -    -    -    -    -    -    */
  569. /*
  570.  * This used to be a label to goto to set the appropriate timeout value
  571.  * and blocked in select(). Now we set selwait and the SELECTARGs to the
  572.  * appropriate values, and in X register a new timeout, then return to
  573.  * allow event processing.
  574.  */
  575. static void
  576. keepWaitingDirsend(void)
  577. {
  578.     /* We come back to this point (by a goto) if the packet */
  579.     /* received is only part of the response, or if the     */
  580.     /* response came from the wrong host            */
  581.  
  582. #ifdef DEBUG
  583.     if (pfs_debug > 2) fprintf(stderr,"Waiting for reply...");
  584. #endif
  585.  
  586. #ifndef CUTCP
  587.     FD_ZERO(&readfds);
  588.     FD_SET(lp, &readfds);
  589. #endif
  590.  
  591.     if(ackpend) selwait = &ackwait;
  592.     else if(gaps) selwait = &gapwait;
  593.     else selwait = &timeout;
  594. }
  595.  
  596. /*    -    -    -    -    -    -    -    -    */
  597. /*
  598.  * This routine is called when a timeout occurs. It includes the code that
  599.  * was formerly used when select() returned 0 (indicating a timeout).
  600.  */
  601. /*ARGSUSED*/
  602. static void
  603. timeoutProc(XtPointer client_data,XtIntervalId *id)
  604. //XtPointer client_data;
  605. //XtIntervalId *id;
  606. {
  607.     if (gaps || ackpend) { /* Send acknowledgment */
  608.     /* Acks are piggybacked on retries - If we have received */
  609.     /* an ack from the server, then the packet sent is only  */
  610.     /* an ack and the rest of the message will be empty      */
  611. #ifdef DEBUG
  612.     if (pfs_debug > 2) {
  613.             fprintf(stderr,"Acknowledging (%s).\n",
  614.             (ackpend ? "requested" : "gaps"));
  615.     }    
  616. #endif
  617.     if (gaps && verbose)
  618.       fprintf (stderr, "Searching...\n");
  619.     retryDirsend();
  620.     return;
  621.     }
  622.  
  623.     if (retries-- > 0) {
  624.     timeout.tv_sec = CLIENT_DIRSRV_BACKOFF(timeout.tv_sec);
  625. #ifdef DEBUG
  626.     if (pfs_debug > 2) {
  627.             fprintf(stderr,"Timed out.  Setting timeout to %d seconds.\n",
  628.             timeout.tv_sec);
  629.     }
  630. #endif
  631.     retryDirsend();
  632.     return;
  633.     }
  634.  
  635. #ifdef DEBUG
  636.     if (pfs_debug) {
  637.     fprintf(stderr, "select failed(timeoutProc): readfds=%x ",
  638.         readfds);
  639.     perror("");
  640.     }
  641. #endif
  642. #ifndef CUTCP
  643.     close(lp);
  644. #endif
  645.     perrno = DIRSEND_SELECT_FAILED;
  646.     ptlfree(first);
  647.     ptlfree(pkt);
  648.     /* return(NULL); */
  649.     dirsendReturn = NULL;
  650.     dirsendDone = DSRET_TIMEOUT;
  651. }
  652.  
  653. /*    -    -    -    -    -    -    -    -    */
  654. /*
  655.  * This function is called whenever there's something to read on the
  656.  * connection. It includes the code that was run when select() returned
  657.  * greater than 0 (indicating read ready).
  658.  */
  659. /*ARGSUSED*/
  660. static void
  661. readProc(XtPointer client_data, int *source, XtInputId *id)
  662. //XtPointer client_data;
  663. //int *source;
  664. //XtInputId *id;
  665. {
  666. #ifdef CUTCP
  667.     int lretry = 3;
  668. #endif
  669.  
  670.     from_sz = sizeof(from);
  671.     next->start = next->dat;
  672.  
  673. #ifndef CUTCP
  674.     if ((nr = recvfrom(lp, next->start, sizeof(next->dat), 0, (struct sockaddr *)&from, &from_sz)) < 0) {
  675. #else
  676.     nr = neturead(next->start);
  677.     if (nr < 1) {
  678. #endif
  679. #ifdef DEBUG
  680.         if (pfs_debug) perror("recvfrom");
  681. #endif
  682. #ifndef CUTCP
  683.     close(lp);
  684. #endif
  685.     perrno = DIRSEND_BAD_RECV;
  686.     ptlfree(first);
  687.     ptlfree(pkt);
  688.     /* return(NULL) */
  689.     dirsendReturn = NULL;
  690.     dirsendDone = DSRET_RECV_ERROR;
  691.         return;
  692.     }
  693.  
  694.     next->length = nr;
  695.     next->start[next->length] = 0;
  696.  
  697. #ifdef DEBUG
  698.     if (pfs_debug > 2)
  699.         fprintf(stderr,"Received packet from %s\n",
  700.         inet_ntoa(SUN_GNU_FIX *(struct in_addr *)&from.sin_addr));
  701. #endif
  702.  
  703.  
  704.     /* For the current format, if the first byte is less than             */
  705.     /* 20, then the first two bits are a version number and the next six  */
  706.     /* are the header length (including the first byte).                  */
  707.     if((hdr_len = (unsigned char) *(next->start)) < 20) {
  708.     ctlptr = next->start + 1;
  709.     next->seq = 0;
  710.     if(hdr_len >= 3) {     /* Connection ID */
  711.         bcopy(ctlptr,&stmp,2);
  712.         if(stmp) pkt_cid = ntohs(stmp);
  713.         ctlptr += 2;
  714.     }
  715.     if(pkt_cid && this_conn_id && (pkt_cid != ntohs(this_conn_id))) {
  716.         /* The packet is not for us */
  717.         /* goto keep_waiting; */
  718.         keepWaitingDirsend();
  719.         return;
  720.     }
  721.     if(hdr_len >= 5) {    /* Packet number */
  722.         bcopy(ctlptr,&stmp,2);
  723.         next->seq = ntohs(stmp);
  724.         ctlptr += 2;
  725.     }
  726.     else { /* No packet number specified, so this is the only one */
  727.         next->seq = 1;
  728.         nd_pkts = 1;
  729.     }
  730.     if(hdr_len >= 7) {        /* Total number of packets */
  731.         bcopy(ctlptr,&stmp,2);  /* 0 means don't know      */
  732.         if(stmp) nd_pkts = ntohs(stmp);
  733.         ctlptr += 2;
  734.     }
  735.     if(hdr_len >= 9) {    /* Receievd through */
  736.         bcopy(ctlptr,&stmp,2);  /* 1 means received request */
  737. #ifndef USE_V3_PROT
  738.         if((stmp) && (ntohs(stmp) == 1)) {
  739.         /* Future retries will be acks only */
  740.         pkt->length = 9;
  741.         bcopy(&zero,pkt->start+3,2);
  742. #ifdef DEBUG
  743.         if(pfs_debug > 2) 
  744.             fprintf(stderr,"Server acked request - retries will be acks only\n");
  745. #endif
  746.         }
  747. #endif
  748.         ctlptr += 2;
  749.     }
  750.     if(hdr_len >= 11) {    /* Backoff */
  751.         bcopy(ctlptr,&stmp,2);
  752.         if(stmp) {
  753.         backoff = (short) ntohs(stmp);
  754. #ifdef DEBUG
  755.         if(pfs_debug > 2) 
  756.             fprintf(stderr,"Backing off to %d seconds\n", backoff);
  757. #endif
  758.         timeout.tv_sec = backoff;
  759.         if ((backoff > 60) && (first == next) && (no_pkts == 0)) {
  760.             /* Probably a long queue on the server - don't give up */
  761.             retries = client_dirsrv_retry;
  762.         }
  763.         }
  764.         ctlptr += 2;
  765.     }
  766.     if(hdr_len >= 12) {    /* Flags (1st byte) */
  767.         bcopy(ctlptr,&rdflag11,1);
  768.         if(rdflag11 & 0x80) {
  769. #ifdef DEBUG
  770.         if(pfs_debug > 2) 
  771.             fprintf(stderr,"Ack requested\n");
  772. #endif
  773.         ackpend++;
  774.         }
  775.         if(rdflag11 & 0x40) {
  776. #ifdef DEBUG
  777.         if(pfs_debug > 2) 
  778.             fprintf(stderr,"Sequenced control packet\n");
  779. #endif
  780.         next->length = -1;
  781.         scpflag++;
  782.         }
  783.         ctlptr += 1;
  784.     }
  785.     if(hdr_len >= 13) {    /* Flags (2nd byte) */
  786.         /* Reserved for future use */
  787.         bcopy(ctlptr,&rdflag12,1);
  788.         ctlptr += 1;
  789.     }
  790.     if(next->seq == 0) {
  791.         /* goto keep_waiting; */
  792.         keepWaitingDirsend();
  793.         return;
  794.     }
  795.     if(next->length >= 0) next->length -= hdr_len;
  796.     next->start += hdr_len;
  797.     goto done_old;
  798.     }
  799.  
  800.     pkt_cid = 0;
  801.  
  802.     /* if intermediate format (between old and new), then process */
  803.     /* and go to done_old                                         */
  804.     ctlptr = next->start + max(0,next->length-20);
  805.     while(*ctlptr) ctlptr++;
  806.     /* Control fields start after the terminating null */
  807.     ctlptr++;
  808.     /* Until old version are gone, must be 4 extra bytes minimum */
  809.     /* When no version 3 servers, can remove the -4              */
  810.     if(ctlptr < (next->start + next->length - 4)) {
  811.     /* Connection ID */
  812.     bcopy(ctlptr,&stmp,2);
  813.     if(stmp) pkt_cid = ntohs(stmp);
  814.     ctlptr += 2;
  815.     if(pkt_cid && this_conn_id && (pkt_cid != ntohs(this_conn_id))) {
  816.         /* The packet is not for us */
  817.         /* goto keep_waiting; */
  818.         keepWaitingDirsend();
  819.         return;
  820.     }
  821.     /* Packet number */
  822.     if(ctlptr < (next->start + next->length)) {
  823.         bcopy(ctlptr,&stmp,2);
  824.         next->seq = ntohs(stmp);
  825.         ctlptr += 2;
  826.     }
  827.     /* Total number of packets */
  828.     if(ctlptr < (next->start + next->length)) {
  829.         bcopy(ctlptr,&stmp,2);
  830.         if(stmp) nd_pkts = ntohs(stmp);
  831.         ctlptr += 2;
  832.     }
  833.     /* Receievd through */
  834.     if(ctlptr < (next->start + next->length)) {
  835.         /* Not supported by clients */
  836.         ctlptr += 2;
  837.     }
  838.     /* Backoff */
  839.     if(ctlptr < (next->start + next->length)) {
  840.         bcopy(ctlptr,&stmp,2);
  841.         backoff = ntohs(stmp);
  842. #ifdef DEBUG
  843.         if(pfs_debug > 2) 
  844.         fprintf(stderr,"Backing off to %d seconds\n", backoff);
  845. #endif
  846.         if (verbose && backoff)
  847.           fprintf (stderr, "Searching...\n");
  848.         if(backoff) timeout.tv_sec = backoff;
  849.         ctlptr += 2;
  850.     }
  851.     if(next->seq == 0) {
  852.         /* goto keep_waiting; */
  853.         keepWaitingDirsend();
  854.         return;
  855.     }
  856.     goto done_old;
  857.  
  858.     }
  859.  
  860.     /* Notes that we have to start searching 11 bytes before the    */
  861.     /* expected start of the MULTI-PACKET line because the message  */
  862.     /* might include up to 10 bytes of data after the trailing null */
  863.     /* The order of those bytes is two bytes each for Connection ID */
  864.     /* Packet-no, of, Received-through, Backoff                     */
  865.     seqtxt = nlsindex(next->start + max(0,next->length - 40),"MULTI-PACKET"); 
  866.     if(seqtxt) seqtxt+= 13;
  867.  
  868.     if((nd_pkts == 0) && (no_pkts == 0) && (seqtxt == NULL)) goto all_done;
  869.  
  870.     tmp = sscanf(seqtxt,"%d OF %d", &(next->seq), &nd_pkts);
  871. #ifdef DEBUG    
  872.     if (pfs_debug && (tmp == 0)) 
  873.     fprintf(stderr,"Cant read packet sequence number: %s", seqtxt);    
  874. #endif
  875.  done_old:
  876. #ifdef DEBUG
  877.     if(pfs_debug > 2) fprintf(stderr,"Packet %d of %d\n",next->seq,nd_pkts);
  878. #endif
  879.     if ((first == next) && (no_pkts == 0)) {
  880.     if(first->seq == 1) {
  881.         comp_thru = first;
  882.         /* If only one packet, then return it */
  883.         if(nd_pkts == 1) goto all_done;
  884.     }
  885.     else gaps++;
  886.     no_pkts = 1;
  887.     next = ptalloc();
  888.     /* goto keep_waiting; */
  889.     keepWaitingDirsend();
  890.     return;
  891.     }
  892.  
  893.     if(comp_thru && (next->seq <= comp_thru->seq))
  894.     ptfree(next);
  895.     else if (next->seq < first->seq) {
  896.     vtmp = first;
  897.     first = next;
  898.     first->next = vtmp;
  899.     first->previous = NULL;
  900.     vtmp->previous = first;
  901.     if(first->seq == 1) comp_thru = first;
  902.     no_pkts++;
  903.     }
  904.     else {
  905.     vtmp = (comp_thru ? comp_thru : first);
  906.     while (vtmp->seq < next->seq) {
  907.         if(vtmp->next == NULL) {
  908.         vtmp->next = next;
  909.         next->previous = vtmp;
  910.         next->next = NULL;
  911.         no_pkts++;
  912.         goto ins_done;
  913.         }
  914.         vtmp = vtmp->next;
  915.     }
  916.     if(vtmp->seq == next->seq)
  917.         ptfree(next);
  918.     else {
  919.         vtmp->previous->next = next;
  920.         next->previous = vtmp->previous;
  921.         next->next = vtmp;
  922.         vtmp->previous = next;
  923.         no_pkts++;
  924.     }
  925.     }   
  926.  
  927. ins_done:
  928.     
  929.     while(comp_thru && comp_thru->next && 
  930.       (comp_thru->next->seq == (comp_thru->seq + 1))) {
  931.     comp_thru = comp_thru->next;
  932. #ifndef USE_V3_PROT
  933.     recvd_thru = htons(comp_thru->seq);
  934.     bcopy(&recvd_thru,pkt->start+7,2); /* Let server know we got it */
  935. #endif
  936.     /* We've made progress, so reset retry count */
  937.     retries = client_dirsrv_retry;
  938.     /* Also, next retry will be only an acknowledgement */
  939.     /* but for now, we can't fill in the ack field      */
  940. #ifdef DEBUG
  941.     if(pfs_debug > 2) 
  942.         fprintf(stderr,"Packets now received through %d\n",comp_thru->seq);
  943. #endif
  944.     }
  945.  
  946.     /* See if there are any gaps */
  947.     if(!comp_thru || comp_thru->next) gaps++;
  948.     else gaps = 0;
  949.  
  950.     if ((nd_pkts == 0) || (no_pkts < nd_pkts)) {
  951.     next = ptalloc();
  952.     /* goto keep_waiting; */
  953.     keepWaitingDirsend();
  954.     return;
  955.     }
  956.  
  957.  all_done:
  958.     if(ackpend) { /* Send acknowledgement if requested */
  959. #ifdef DEBUG
  960.     if (pfs_debug > 2) {
  961.         if (to.sin_family == AF_INET)
  962.         fprintf(stderr,"Acknowledging final packet to %s(%d)\n",
  963.             to_hostname, ntohs(this_conn_id));
  964.             else
  965.                 fprintf(stderr,"Acknowledging final packet\n");
  966.         (void) fflush(stderr);
  967.     }
  968. #endif
  969. #ifndef CUTCP
  970.     ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  971. #else
  972.     while(--lretry) {
  973.         ns = netusend(&to.sin_addr, ntohs(to.sin_port), ntohs(us.sin_port),(char *) pkt->start, pkt->length);
  974.         if(!ns)
  975.             break;
  976.         Stask();
  977.         Stask();
  978.     }
  979. #endif
  980.  
  981. #ifndef CUTCP
  982.     if(ns != pkt->length) {
  983. #else
  984.     if(ns != 0) {
  985. #endif
  986.  
  987. #ifdef DEBUG
  988.         if (pfs_debug) {
  989.         fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  990.         perror("");
  991.         }
  992. #endif
  993.     }
  994.  
  995.     }
  996. #ifndef CUTCP
  997.     close(lp);
  998. #endif
  999.     ptlfree(pkt);
  1000.  
  1001.     /* Get rid of any sequenced control packets */
  1002.     if(scpflag) {
  1003.     while(first && (first->length < 0)) {
  1004.         vtmp = first;
  1005.         first = first->next;
  1006.         if(first) first->previous = NULL;
  1007.         ptfree(vtmp);
  1008.     }
  1009.     vtmp = first;
  1010.     while(vtmp && vtmp->next) {
  1011.         if(vtmp->next->length < 0) {
  1012.         if(vtmp->next->next) {
  1013.             vtmp->next = vtmp->next->next;
  1014.             ptfree(vtmp->next->previous);
  1015.             vtmp->next->previous = vtmp;
  1016.         }
  1017.         else {
  1018.             ptfree(vtmp->next);
  1019.             vtmp->next = NULL;
  1020.         }
  1021.         }
  1022.         vtmp = vtmp->next;
  1023.     }
  1024.     }
  1025.  
  1026.     /* return(first); */
  1027.     dirsendReturn = first;
  1028.     dirsendDone = DSRET_DONE;
  1029.  
  1030. }
  1031.  
  1032. static void
  1033. processEvent(void)
  1034. {
  1035. #ifdef CUTCP
  1036.     unsigned long now;
  1037. #endif
  1038.     /* select - either recv is ready, or timeout */
  1039.     /* see if timeout or error or wrong descriptor */
  1040. #ifndef CUTCP
  1041.     tmp = select(lp + 1, &readfds, (SELECTARG *)0, (SELECTARG *)0, selwait);
  1042.     if (tmp == 0) {
  1043.     timeoutProc(NULL,&timerId);
  1044.     } else if ((tmp < 0) || !FD_ISSET(lp,&readfds)) {
  1045. #ifdef DEBUG
  1046.     if (pfs_debug) {
  1047.         fprintf(stderr, "select failed(processEvent): readfds=%x ",
  1048.             readfds);
  1049.         perror("");
  1050.     }
  1051. #endif
  1052.     close(lp);
  1053. #else /* CUTCP's flood. */
  1054.     /* while not timeout in selwait loop, stask looking for uevents */
  1055.     now = time(NULL) + selwait->tv_sec;
  1056. #ifdef    DEBUG
  1057.      if(pfs_debug) {
  1058.         fprintf(stderr,"Waiting %d seconds\n",selwait->tv_sec);
  1059.     }
  1060.  
  1061. #endif
  1062.     while(now > time(NULL)) {
  1063.         int    i, cl, dat;
  1064.  
  1065.         Stask();
  1066.         if (0 < (i = Sgetevent(USERCLASS, &cl, &dat))) {
  1067.             /* got a user class event */
  1068.             if(cl == USERCLASS &&
  1069.                 i == UDPDATA) {
  1070.                     readProc(NULL,&lp,&inputId);
  1071.                     return;
  1072.             }
  1073.         }
  1074.         if(kbhit()) {
  1075.             int c = getch();
  1076.             if(c == 27 || c == 3)
  1077.                 break;
  1078.             fprintf(stderr,"Press <ESCAPE> to abort\n");
  1079.         }
  1080.     }
  1081.     if(now <= time(NULL)) {    /* timeout */
  1082.         timeoutProc(NULL,&timerId);
  1083.          return;
  1084.     }
  1085.  
  1086. #endif /* CUTCP */
  1087.     perrno = DIRSEND_SELECT_FAILED;
  1088.     ptlfree(first);
  1089.     ptlfree(pkt);
  1090.     /* return(NULL); */
  1091.     dirsendReturn = NULL;
  1092.     dirsendDone = DSRET_SELECT_ERROR;
  1093. #ifndef CUTCP
  1094.     } else {
  1095.     readProc(NULL,&lp,&inputId);
  1096.     }
  1097. #endif /* CUTCP */
  1098. }
  1099.  
  1100. void
  1101. abortDirsend(void)
  1102. {
  1103.     if (!dirsendDone) {
  1104. #ifndef CUTCP
  1105.     close(lp);
  1106. #endif
  1107.     ptlfree(first);
  1108.     ptlfree(pkt);
  1109.     dirsendReturn = NULL;
  1110.     dirsendDone = DSRET_ABORTED;
  1111.     }
  1112.     return;
  1113. }
  1114.